feat(rocm): MoE combine/gate ops — SharedExpertGate, MoeCombine, MoeCombineGate (issue #41) - #509
feat(rocm): MoE combine/gate ops — SharedExpertGate, MoeCombine, MoeCombineGate (issue #41)#509VikashLoomba wants to merge 3 commits into
Conversation
|
Reviewed as part of a sweep over the open external PRs. The translations are faithful — I checked all three donor anchors at your base SHA and they resolve exactly ( Two things to fix. Both are the same shape as findings on #506 and #523 — the calculation ported cleanly, the guards around it did not — so it is probably worth reading the three together. 1. The donor's dtype refusals were dropped, and f16 is reachable.
f16 gets through: 2. The new test exercises the dtype arm the model never runs. On the live path Consequence: an inverted predicate in Smaller ones: Credit where due: recomputing the No AMD hardware here, so your 9/9 and the ctest results could not be reproduced and I am not disputing them; both findings are static, read from the seam and the model path. |
…ms -- the mudler#509 review rework Review sweep findings (localai-bot, 2026-08-13), all accepted: 1. The donor's dtype refusals were dropped: cuda_moe.cu:520-524/:597-604 open with VT_CHECKs refusing non-f32/bf16; without them an f16 expert_out passes the seam's IsFloat gate and Tensor::Ptr<T>()'s unchecked cast reads 4 bytes per element from a 2-byte allocation. Refusals added to all three ROCm entry points (SharedExpertGate included: its 4-arm dispatch has the same f16 hazard on sd). 2. The case now exercises the PRODUCTION dtype mix, not only f32: the model path runs expert_out bf16 (qwen3_5.cpp DBuf ddown), shared bf16, out bf16. The new bf16 arm is asserted BIT-EXACT against the CPU reference (both sides thread-per-element, same sequential K order, single store rounding, -ffp-contract=off), and the f32 MoeCombine arm is tightened from NMSE to bit-exact per the donor's design comment (cuda_moe.cu:465-468). Writing the bf16 arm caught a construction bug in the first version of it (an f32-typed tensor over a bf16 buffer -- exactly the OOB class the review predicted the missing arm hid); fixed and re-verified against an independent host composite (0/320) plus a raw-hipMalloc scratch replica of both backends. 3. CMakeLists.txt: the mangled duplicate rocm_moe_chain.hip line removed. 4. docs/FEATURES.md op count 44 -> 47 (counted: the registration sites). Gates (gfx1100, flock): test_backend_cross_device 20/20 (bit-exact bf16 + f32 arms). FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: pi:kimi-k3 [pi]
8a4ed36 to
ebb4c6b
Compare
|
Both findings accepted and reworked (commits dfd1213 + ebb4c6b, rebased onto current main):
Also: the mangled duplicate Gates: |
…ms -- the mudler#509 review rework Review sweep findings (localai-bot, 2026-08-13), all accepted: 1. The donor's dtype refusals were dropped: cuda_moe.cu:520-524/:597-604 open with VT_CHECKs refusing non-f32/bf16; without them an f16 expert_out passes the seam's IsFloat gate and Tensor::Ptr<T>()'s unchecked cast reads 4 bytes per element from a 2-byte allocation. Refusals added to all three ROCm entry points (SharedExpertGate included: its 4-arm dispatch has the same f16 hazard on sd). 2. The case now exercises the PRODUCTION dtype mix, not only f32: the model path runs expert_out bf16 (qwen3_5.cpp DBuf ddown), shared bf16, out bf16. The new bf16 arm is asserted BIT-EXACT against the CPU reference (both sides thread-per-element, same sequential K order, single store rounding, -ffp-contract=off), and the f32 MoeCombine arm is tightened from NMSE to bit-exact per the donor's design comment (cuda_moe.cu:465-468). Writing the bf16 arm caught a construction bug in the first version of it (an f32-typed tensor over a bf16 buffer -- exactly the OOB class the review predicted the missing arm hid); fixed and re-verified against an independent host composite (0/320) plus a raw-hipMalloc scratch replica of both backends. 3. CMakeLists.txt: the mangled duplicate rocm_moe_chain.hip line removed. 4. docs/FEATURES.md op count 44 -> 47 (counted: the registration sites). Gates (gfx1100, flock): test_backend_cross_device 20/20 (bit-exact bf16 + f32 arms). FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: pi:kimi-k3 [pi]
ebb4c6b to
859a666
Compare
859a666 to
d5fb6eb
Compare
…ms -- the mudler#509 review rework Review sweep findings (localai-bot, 2026-08-13), all accepted: 1. The donor's dtype refusals were dropped: cuda_moe.cu:520-524/:597-604 open with VT_CHECKs refusing non-f32/bf16; without them an f16 expert_out passes the seam's IsFloat gate and Tensor::Ptr<T>()'s unchecked cast reads 4 bytes per element from a 2-byte allocation. Refusals added to all three ROCm entry points (SharedExpertGate included: its 4-arm dispatch has the same f16 hazard on sd). 2. The case now exercises the PRODUCTION dtype mix, not only f32: the model path runs expert_out bf16 (qwen3_5.cpp DBuf ddown), shared bf16, out bf16. The new bf16 arm is asserted BIT-EXACT against the CPU reference (both sides thread-per-element, same sequential K order, single store rounding, -ffp-contract=off), and the f32 MoeCombine arm is tightened from NMSE to bit-exact per the donor's design comment (cuda_moe.cu:465-468). Writing the bf16 arm caught a construction bug in the first version of it (an f32-typed tensor over a bf16 buffer -- exactly the OOB class the review predicted the missing arm hid); fixed and re-verified against an independent host composite (0/320) plus a raw-hipMalloc scratch replica of both backends. 3. CMakeLists.txt: the mangled duplicate rocm_moe_chain.hip line removed. 4. docs/FEATURES.md op count 44 -> 47 (counted: the registration sites). Gates (gfx1100, flock): test_backend_cross_device 20/20 (bit-exact bf16 + f32 arms). FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: pi:kimi-k3 [pi]
…mbineGate) (mudler#41) The next links in the generic MoE path after the router/silu-mul. Hand- translated from cuda_moe.cu (MoeCombineKernel :473, MoeCombineGateKernel :555) and the SharedExpertGate CPU oracle (cpu_ops.cpp:2387). Grid-stride, f32 math, bf16/f32 dtype arms via boundary conversions; the combine-gate folds the shared-expert sigmoid gate rounded through bf16 exactly as the donor. Evidence (4x gfx1100, ROCm 7.14, Release): - new MoE combine/gate cross-device case: 9/9 assertions (MoeCombineGate's oracle is the host-computed composite — no CPU op registration exists) - ctest -R 'rocm|cross_device': 4/4 - full ctest: pre-existing failure set shrinks 7 -> 5; test_bench and test_capi now PASS (they failed at op 77 / the router dtype before the chain). test_loaded_engine_dense now fails only on the async-scheduling assertion (a lane capability gap, not a kernel throw). - Named remaining blocker: the grouped quant expert GEMM (kMatmulBTQuantGrouped), the DeepSeek-V4 keep-quant family. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: pi:kimi-k3 [pi]
…ms -- the mudler#509 review rework Review sweep findings (localai-bot, 2026-08-13), all accepted: 1. The donor's dtype refusals were dropped: cuda_moe.cu:520-524/:597-604 open with VT_CHECKs refusing non-f32/bf16; without them an f16 expert_out passes the seam's IsFloat gate and Tensor::Ptr<T>()'s unchecked cast reads 4 bytes per element from a 2-byte allocation. Refusals added to all three ROCm entry points (SharedExpertGate included: its 4-arm dispatch has the same f16 hazard on sd). 2. The case now exercises the PRODUCTION dtype mix, not only f32: the model path runs expert_out bf16 (qwen3_5.cpp DBuf ddown), shared bf16, out bf16. The new bf16 arm is asserted BIT-EXACT against the CPU reference (both sides thread-per-element, same sequential K order, single store rounding, -ffp-contract=off), and the f32 MoeCombine arm is tightened from NMSE to bit-exact per the donor's design comment (cuda_moe.cu:465-468). Writing the bf16 arm caught a construction bug in the first version of it (an f32-typed tensor over a bf16 buffer -- exactly the OOB class the review predicted the missing arm hid); fixed and re-verified against an independent host composite (0/320) plus a raw-hipMalloc scratch replica of both backends. 3. CMakeLists.txt: the mangled duplicate rocm_moe_chain.hip line removed. 4. docs/FEATURES.md op count 44 -> 47 (counted: the registration sites). Gates (gfx1100, flock): test_backend_cross_device 20/20 (bit-exact bf16 + f32 arms). FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: pi:kimi-k3 [pi]
…#684) plumbed through the ROCm arm The rebase onto current main brought main's new MoeCombineFn signature (routed_scale, default 1.0f, scaling the ROUTED sum before the shared term -- upstream apply_routed_scale_to_output). The ROCm kernel applies it in the same f32 accumulator in the same order (one standalone multiply on the finished sum, bit-identical to the CPU reference under -ffp-contract=off); the forward declaration in rocm_ops.hip is updated to match. The bf16 test arm now runs at scale 0.7 so the multiply is exercised, not just the 1.0 passthrough. Gates (gfx1100, flock): test_backend_cross_device 20/20 (bit-exact arms unchanged at 1.0, bit-exact at 0.7). FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: pi:kimi-k3 [pi]
d5fb6eb to
9aefaec
Compare
Row
BACKEND-ROCM— the next links in the generic MoE path, after the router/silu-mul (#348). Issue #41. ClaimCLAIM-ROCM-GDN-KERNELScontinues.What changed
NEW
src/vt/rocm/rocm_moe_chain.hipwith three ops, hand-translated fromcuda_moe.cu(MoeCombineKernel:473,MoeCombineGateKernel:555) + theSharedExpertGateCPU oracle (cpu_ops.cpp:2387):kSharedExpertGate—out[t,c] = sigmoid(gl[t]) * sd[t,c](bf16 out, f32/bf16 sd)kMoeCombine— weighted top-k expert sum + optional shared termkMoeCombineGate— combine with the shared-expert sigmoid gate folded in, the shared term rounded through bf16 exactly as the donorAll grid-stride, f32 math, bf16/f32 dtype arms via boundary conversions. New cross-device case gates all three (MoeCombineGate's oracle is the host-computed composite — no CPU op registration exists for it).
Evidence (4× gfx1100, ROCm 7.14, Release)
ctest -R 'rocm|cross_device': 4/4test_benchandtest_capinow PASS (they failed at op 77 / the router dtype before the chain).test_loaded_engine_densenow fails only on the async-scheduling assertion (runner_supports_async()=falseon ROCm), a lane capability gap, not a kernel throw.Speed claims
Honest gaps
kMatmulBTQuantGrouped, the DeepSeek-V4 keep-quant family) — the heavy lift for Qwen3.5-27B-class GDN-MoE models, a proper kernel project of its own.